package com.example.livereplay.common.service.imp;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.livereplay.common.model.enity.FFmpegUtils;
import com.example.livereplay.common.model.enity.LiveStream;
import com.example.livereplay.common.model.enity.Place;
import com.example.livereplay.common.model.enity.Tournament;
import com.example.livereplay.common.service.LiveStreamService;
import com.example.livereplay.common.service.PlaceService;
import com.example.livereplay.common.service.TournamentService;
import com.example.livereplay.exception.BusinessException;
import com.example.livereplay.common.mapper.LiveStreamMapper;
import com.example.livereplay.common.mapper.PlaceMapper;
import com.example.livereplay.common.mapper.TournamentMapper;
import com.example.livereplay.common.model.request.CreateLiveStreamRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class LiveStreamImpl extends ServiceImpl<LiveStreamMapper, LiveStream> implements LiveStreamService {

 @Resource
 private TournamentMapper tournamentMapper;

 @Resource
 private PlaceService placeService;

 @Resource
 private TournamentService tournamentService;

 @Resource
 private PlaceMapper placeMapper;

 @Resource
 private LiveStreamMapper liveStreamMapper;

    private static final String FFMPEG_PATH = "/usr/bin/ffmpeg";

    private static final String VIDEO_CODEC = "libx264";

    private static final String AUDIO_CODEC = "aac";

    private static final String OUTPUT_FORMAT = "flv";


    @Transactional(rollbackFor = Exception.class)
    @Override
    public LiveStream createLiveStream(CreateLiveStreamRequest createLiveStreamRequest)
    {
     final Tournament tournament = tournamentMapper.selectOne(new LambdaQueryWrapper<Tournament>()
             .eq(Tournament::getName,createLiveStreamRequest.getName())
             .eq(Tournament::getGameEndTime,createLiveStreamRequest.getGameEndTime())
             .eq(Tournament::getGameStartTime,createLiveStreamRequest.getGameStartTime())
     );
     final Place place =new Place();
     if(tournament==null)
     {
      tournament.setName(createLiveStreamRequest.getName());
      tournament.setGameStartTime(createLiveStreamRequest.getGameStartTime());
      tournament.setGameEndTime(createLiveStreamRequest.getGameEndTime());
      if (tournamentService.save(tournament)) {
       place.setTournamentId(tournament.getId());
       place.setName(createLiveStreamRequest.getPlaceName());
       placeService.save(place);
      }
     }
     else{
      final Place newOne=placeMapper.selectOne(new LambdaQueryWrapper<Place>()
              .eq(Place::getName,createLiveStreamRequest.getPlaceName())
              .eq(Place::getTournamentId,tournament.getId())
      );
      if(newOne!=null) {
       BeanUtil.copyProperties(newOne, place);
      }
      else{
       return null;
      }
     }
     final LiveStream liveStream=new LiveStream();
     liveStream.setPlaceId(place.getId());
     liveStream.setUserId(createLiveStreamRequest.getUserId());
     liveStream.setStartTime(createLiveStreamRequest.getPlaceStartTime());
     liveStream.setEndTime(createLiveStreamRequest.getPlaceEndTime());
     String pushUrl = "rtmp://your_server/live/" + liveStream.getId();
     String pullUrl = "http://your_server/watch/" + liveStream.getId();
     liveStream.setPushUrl(pushUrl);
     liveStream.setPullUrl(pullUrl);
     liveStream.setStatus("SCHEDULED");
     if (save(liveStream))
     {
      return liveStream;
     }
     return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public LiveStream startLiveStream(String liveStreamId) {
        LiveStream liveStream = liveStreamMapper.selectById(liveStreamId);
        if (liveStream == null) {
            throw new IllegalArgumentException("直播不存在");
        }

        liveStream.setStatus("LIVE");
        long curentTime=System.currentTimeMillis();
        liveStream.setStartTime(curentTime);

        liveStreamMapper.updateById(liveStream);

        try {
            String inputPath = "/dev/video0";
            String audioInputPath = "default";
            Process pushStreamProcess = FFmpegUtils.startPushStream(FFMPEG_PATH, inputPath, audioInputPath, liveStream.getPushUrl(), VIDEO_CODEC, AUDIO_CODEC, OUTPUT_FORMAT);
            new Thread(() -> {
                try {
                    int exitCode = pushStreamProcess.waitFor();
                    if (exitCode!= 0) {
                        liveStream.setStatus("ERROR");
                        liveStreamMapper.updateById(liveStream);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();

        } catch (IOException e) {
            e.printStackTrace();
            liveStream.setStatus("FAIL");
            liveStreamMapper.updateById(liveStream);
            throw new RuntimeException("推流启动失败");
        }

        return liveStream;
    }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public List<LiveStream> getLiveStreamsByPlaceId(String placeId)
  {
    final Place place=placeMapper.selectById(placeId);
    if(place==null)
    {
     throw new BusinessException("没有对应的场地");
    }
    final List<LiveStream> liveStreams=list(new LambdaQueryWrapper<LiveStream>().eq(LiveStream::getPlaceId,placeId));
    if(liveStreams==null)
    {
     return new ArrayList<>();
    }
    return liveStreams;
  }
}
